package config

import (
	"github.com/bwmarrin/snowflake"
	"github.com/go-viper/mapstructure/v2"
	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/sdk/trace"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"xincan.com.cn/tarot-go/internal/common/constants"
	"xincan.com.cn/tarot-go/internal/common/types"
	"xincan.com.cn/tarot-go/internal/components/id"
	"xincan.com.cn/tarot-go/internal/components/logging"
	"xincan.com.cn/tarot-go/internal/components/validator"
	"xincan.com.cn/tarot-go/internal/config/factory"
	"xincan.com.cn/tarot-go/internal/config/loader"
	"xincan.com.cn/tarot-go/internal/utils"
)

// ApplicationConfigLoader
// Title    			ApplicationConfigLoader
// Description 			全局参数配置接口
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
type ApplicationConfigLoader interface {

	// LoggerLoad   获取日志配置实例
	LoggerLoad() (*logging.TraceLogger, *zap.SugaredLogger)

	// ConfigLoad   获取全局参数配置实例
	ConfigLoad() (*types.Service, *viper.Viper)

	// WatchRemoteConfigLoad   监听远程读取配置, 监听回调函数
	WatchRemoteConfigLoad(callback factory.ConfigWatchRemoteConfigLoadFunc)

	// MergeWatchRemoteConfigLoad  合并远程配置信息
	MergeWatchRemoteConfigLoad(watchViper *viper.Viper) *types.Service

	// TraceLoad  获取链路追踪配置实例
	TraceLoad()

	// IdLoad   获取id配置实例
	IdLoad() *snowflake.Node

	// ValidateLoad   验证配置信息
	ValidateLoad() *validator.Validator

	// RegistryLoad   加载配置中心配置信息
	RegistryLoad()

	// CacheLoad   缓存配置信息
	CacheLoad() *redis.Client

	// OrmLoad   数据库配置信息
	OrmLoad() *gorm.DB
}

// applicationConfigLoader
// Title    			applicationConfigLoader
// Description 			全局参数配置
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
type applicationConfigLoader struct {
	provider   constants.ProviderType // 配置提供者
	localViper *viper.Viper           // 本地配置实例
	app        *types.Service         // 基础系统配置
	logger     *logging.TraceLogger   // 日志追踪实例
	sugar      *zap.SugaredLogger     // 日志追踪实例
	node       *snowflake.Node        // 雪花算法实例
	validate   *validator.Validator   // 验证配置信息
	rdb        *redis.Client          // 缓存实例
	ormConfig  *gorm.Config           // 数据库配置信息
	ormDB      *gorm.DB               // 数据库实例
}

// ApplicationConfigLoaderBuilder
// Title    			ApplicationConfigLoaderBuilder
// Description   		全局参数配置构建器
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
type ApplicationConfigLoaderBuilder struct {
	*applicationConfigLoader
}

// NewApplicationConfigBuilder
// Title    			NewApplicationConfigBuilder
// Description   		创建全局参数配置构建器实例
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
// Return    			*ApplicationConfigLoaderBuilder     	全局参数配置构建器实例
func NewApplicationConfigBuilder() *ApplicationConfigLoaderBuilder {
	return &ApplicationConfigLoaderBuilder{
		applicationConfigLoader: &applicationConfigLoader{},
	}
}

// WidthLogger
// Title    			WidthLogger
// Description   		构造器: 加载日志配置
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
// Return    			*ApplicationConfigLoaderBuilder     	全局参数配置构建器实例
func (builder *ApplicationConfigLoaderBuilder) WidthLogger() *ApplicationConfigLoaderBuilder {
	// 1. 加载本地配置, 获取viper实例, 配置实例
	localViper, configFile := loader.NewLocalApplicationConfigLoaderBuilder().Build()
	builder.localViper = localViper
	// 2. 加载日志配置
	builder.logger, builder.sugar = logging.NewApplicationLoggerConfigBuilder().WithLocalViper(localViper).Build()
	builder.logger.Info("当前系统配置环境", zap.String("active", localViper.GetString("application.active")), zap.String("configFile", configFile))
	builder.logger.Info("本地初始配置信息", zap.Any("app", localViper.AllSettings()))
	return builder
}

// Build
// Title    			Build
// Description   		构建全局参数配置实例
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
// Return    			*applicationConfig     					全局参数配置实例
// noinspection
func (builder *ApplicationConfigLoaderBuilder) Build() ApplicationConfigLoader {
	return builder.applicationConfigLoader
}

// LoggerLoad
// Title    			LoggerLoad
// Description   		全局参数配置日志, 根据配置类型获取对应的日志实例
// Author  				alittlexincan@163.com 										2024/07/17 11:36
// Update  				alittlexincan@163.com 										2024/07/17 11:36
// Return    			*logging.TraceLogger     									日志追踪实例
// Return    			*zap.SugaredLogger     										日志实例
func (ac *applicationConfigLoader) LoggerLoad() (*logging.TraceLogger, *zap.SugaredLogger) {
	return ac.logger, ac.sugar
}

// ConfigLoad
// Title    			ConfigLoad
// Description   		获取全局参数配置实例
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
// Return    			*core.Service     						全局参数配置实例
// Return    			*viper.Viper     						全局参数配置实例
func (ac *applicationConfigLoader) ConfigLoad() (*types.Service, *viper.Viper) {
	// 1. 加载本地配置
	localViper := ac.localViper
	// 2. 按需加载远程配置
	loader.NewRemoteApplicationConfigLoaderBuilder().WithLogger(ac.logger).WithLocalViper(localViper).Build()
	// 3. 加载环境变量配置
	loader.NewEnvApplicationConfigLoaderBuilder().WithLogger(ac.logger).WithLocalViper(localViper).Build()
	// 4. 补充本机ip
	ac.localViper.Set("application.ip", utils.GetLocalIP()[0])
	// 5. 映射结构体
	app := &types.Service{}
	if err := ac.localViper.Unmarshal(&app); err != nil {
		ac.logger.Error("加载整体配置信息: 映射结构体失败", zap.Error(err))
	}
	// 6. 打印配置信息
	ac.logger.Info("加载整体配置信息", zap.Any("app", app))
	// 7. 设置结构体参数, 当前采用配置中心参数类型
	ac.provider = constants.ProviderType(localViper.GetString("application.config.provider"))
	ac.app = app
	return app, localViper
}

// WatchRemoteConfigLoad
// Title    			WatchRemoteConfigLoad
// Description   		监听远程读取配置, 更新全局配置实例
// Author      			alittlexincan@163.com       											2024/07/17 11:36
// Update    			alittlexincan@163.com       											2024/07/17 11:36
// Param    			callback 					factory.ConfigWatchRemoteConfigLoadFunc 	监听回调函数
func (ac *applicationConfigLoader) WatchRemoteConfigLoad(callback factory.ConfigWatchRemoteConfigLoadFunc) {
	if ac.provider == "" || ac.provider == constants.ProviderConfigNone {
		ac.logger.Error("监听远程配置失败: 当前配置类型为", zap.Any("provider", ac.provider))
		return
	}
	factory.GetConfigFactory(ac.provider).WatchRemoteConfigLoad(func(watchViper *viper.Viper) {
		callback(watchViper)
	})
}

// MergeWatchRemoteConfigLoad
// Title    			MergeWatchRemoteConfigLoad
// Description   		远程配置信息更新
// Author      			alittlexincan@163.com       					2024/07/22 11:36
// Update    			alittlexincan@163.com       					2024/07/22 11:36
// Param    			watchViper 				*viper.Viper			远程配置信息
// Return    			*core.Service     								全局参数配置实例
func (ac *applicationConfigLoader) MergeWatchRemoteConfigLoad(watchViper *viper.Viper) *types.Service {
	// 1: 获取配置信息
	settings := watchViper.AllSettings()
	if settings == nil {
		ac.logger.Info("远程配置没有变化")
		return ac.app
	}
	// 2: 映射配置信息, 追加覆盖本地配置信息
	for k, v := range settings {
		ac.localViper.Set(k, v)
	}
	ac.logger.Info("远程配置发生变化", zap.Any("remote", settings))
	// 3: 更新系统配置信息
	app := &types.Service{}
	if err := ac.localViper.Unmarshal(&app); err != nil {
		ac.logger.Error("加载整体配置信息: 映射结构体失败: ", zap.Error(err))
	}
	ac.logger.Info("更新系统配置信息", zap.Any("data", app))
	return app
}

// TraceLoad
// Title    			TraceLoad
// Description   		全局参数配置 - 链路追踪
// Author  				alittlexincan@163.com 										2024/07/17 11:36
// Update  				alittlexincan@163.com 										2024/07/17 11:36
func (ac *applicationConfigLoader) TraceLoad() {
	tp := trace.NewTracerProvider(
		trace.WithSampler(trace.AlwaysSample()),
	)
	otel.SetTracerProvider(tp)
}

// IdLoad
// Title    			IdLoad
// Description   		全局参数配置雪花算法
// Author  				alittlexincan@163.com 										2024/07/17 11:36
// Update  				alittlexincan@163.com 										2024/07/17 11:36
// Return    			*snowflake.Node     										雪花算法配置实例
func (ac *applicationConfigLoader) IdLoad() *snowflake.Node {
	node := id.NewSnowflakeIdComponentBuilder().WithLogger(ac.logger).WithApplicationConfig(ac.app).Build()
	ac.node = node
	return node
}

// ValidateLoad
// Title    			ValidateLoad
// Description   	    全局参数配置 - 参数验证器, 根据配置类型获取对应的验证器实例
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
func (ac *applicationConfigLoader) ValidateLoad() *validator.Validator {
	validate := validator.NewPlaygroundValidatorComponentBuilder().WithLogger(ac.logger).Build()
	ac.validate = validate
	return ac.validate
}

// RegistryLoad
// Title    			RegistryLoad
// Description   		全局参数配置注册中心, 根据配置类型获取对应的注册中心实例
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
func (ac *applicationConfigLoader) RegistryLoad() {
	config := ac.app.Config.RegistryCenter
	if config.Provider == "" || config.Provider == constants.ProviderRegistryNone {
		ac.logger.Error("暂无注册中心配置: 当前注册类型为", zap.Any("provider", config.Provider))
		return
	}
	ac.logger.Info("加载注册中心配置: 当前注册类型为", zap.Any("provider", config.Provider))
	instance := factory.GetRegistryFactory(config.Provider)
	data := config.Center[config.Provider.Value()]
	if err := mapstructure.WeakDecode(data, &instance); err != nil {
		ac.logger.Error("解析注册中心失败", zap.Error(err))
	}
	// 注入自身具体结构体实例, 添加日志接口, 添加配置信息
	instance.SetSelf(instance).WithLogger(ac.logger).WithApplicationConfig(ac.app).ConfigLoad()
}

// CacheLoad
// Title    			CacheLoad
// Description   	    全局参数配置缓存, 根据配置类型获取对应的缓存实例
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
// Return    			*redis.Client     						缓存实例
func (ac *applicationConfigLoader) CacheLoad() *redis.Client {
	config := ac.app.Config.CacheCenter
	if config.Provider == "" || config.Provider == constants.ProviderCacheNone {
		ac.logger.Error("暂无缓存信息配置: 当前缓存类型为", zap.Any("provider", config.Provider))
		return nil
	}
	ac.logger.Info("加载缓存信息配置: 当前缓存类型为", zap.Any("provider", config.Provider))
	instance := factory.GetCacheFactory(config.Provider)
	data := config.Center[config.Provider.Value()]
	if err := mapstructure.WeakDecode(data, &instance); err != nil {
		ac.logger.Error("解析缓存信息失败", zap.Error(err))
	}
	// 注入自身具体结构体实例, 添加日志接口, 添加配置信息, 获取缓存实例
	client, _ := instance.SetSelf(instance).WithLogger(ac.logger).WithApplicationConfig(ac.app).ConfigLoad()
	ac.rdb = client
	return client
}

// OrmLoad
// Title    			OrmLoad
// Description   	    全局参数配置 - 对象关系映射配置: 根据配置类型获取对应的缓存实例
// Author  				alittlexincan@163.com 					2024/07/17 11:36
// Update  				alittlexincan@163.com 					2024/07/17 11:36
// Return    			*gorm.DB     							数据库实例
func (ac *applicationConfigLoader) OrmLoad() *gorm.DB {
	config := ac.app.Config.Database
	if config == nil || config.Orm == nil {
		ac.logger.Error("暂无关系映射配置: 关系映射类型为", zap.Any("provider", constants.ProviderOrmGorm))
		return nil
	}
	ac.logger.Info("加载关系映射配置: 关系映射类型为", zap.Any("provider", constants.ProviderOrmGorm))
	ormInstance := factory.GetOrmFactory(constants.ProviderOrmGorm)
	ormData := config.Orm[constants.ProviderOrmGorm.Value()]
	if err := utils.MapstructureDecode(ormData, &ormInstance); err != nil {
		ac.logger.Error("解析关系映射信息失败", zap.Error(err))
	}
	// 注入自身具体结构体实例, 添加日志接口, 添加配置信息, 获取orm配置
	ormConfig, _ := ormInstance.SetSelf(ormInstance).WithLogger(ac.logger).WithApplicationConfig(ac.app).ConfigLoad()
	// 获取数据库实例
	ormDB, _ := ac.WithDatabase(config).WithLogger(ac.logger).WithApplicationConfig(ac.app).WithOrmConfig(ormConfig).ConfigLoad()
	ac.ormConfig = ormConfig
	ac.ormDB = ormDB
	return ormDB
}

// WithDatabase
// Title    			WithDatabase
// Description   	    数据库信息配置: 根据配置类型获取对应的数据库实例
// Author  				alittlexincan@163.com 						2024/07/17 11:36
// Update  				alittlexincan@163.com 						2024/07/17 11:36
// Param    			config 					*core.Database 		数据库信息配置
// Return    			factory.ApplicationDatabaseLoaderFactory 	数据库实例
func (ac *applicationConfigLoader) WithDatabase(config *types.Database) factory.ApplicationDatabaseLoaderFactory {
	if config.Provider == "" || config.Provider == constants.ProviderDatabaseNone {
		ac.logger.Error("暂无存储信息配置: 当前存储类型为", zap.Any("provider", config.Provider))
		return nil
	}
	ac.logger.Info("加载存储信息配置: 当前存储类型为", zap.Any("provider", config.Provider))
	instance := factory.GetDatabaseFactory(config.Provider)
	sql := config.SQL[config.Provider.Value()]
	if err := utils.MapstructureDecode(sql, &instance); err != nil {
		ac.logger.Error("解析存储信息失败", zap.Error(err))
	}
	// 注入自身具体结构体实例
	return instance.SetSelf(instance)
}
